package com.lagou.session;

import com.lagou.enums.SqlCommandType;
import com.lagou.executor.Executor;
import com.lagou.executor.SimpleExecutor;
import com.lagou.pojo.Configuration;
import com.lagou.pojo.MappedStatement;

import java.lang.reflect.*;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @ClassName: DefaultSqlSession
 * @Auther: Jerry
 * @Date: 2020/6/20 9:07
 * @Desctiption: TODO
 * @Version: 1.0
 */
public class DefaultSqlSession implements SqlSession {

    private Configuration configuration;
    private Executor executor = new SimpleExecutor();
    public DefaultSqlSession(Configuration configuration){
        this.configuration = configuration;
    }

    @Override
    public <E> List<E> selectList(String statementId, Object... params) throws Exception {
        MappedStatement mappedStatement = configuration.getMappedStatementMap().get(statementId);
        // 执行jdbc操作
        List<Object> list = executor.query(configuration, mappedStatement, params);

        return (List<E>) list;
    }

    @Override
    public <T> T selectOne(String statementId, Object... params) throws Exception {
        List<Object> list = this.selectList(statementId, params);
        if (list.size() == 1) {
            return (T) list.get(0);
        } else {
            throw new RuntimeException("查询结果为空或查询结果为多条！");
        }
    }

    @Override
    public int insert(String statementId, Object... params) throws ClassNotFoundException, SQLException,
            NoSuchFieldException, IllegalAccessException, InstantiationException {
        MappedStatement mappedStatement = configuration.getMappedStatementMap().get(statementId);
        return executor.insert(configuration, mappedStatement, params);
    }

    @Override
    public int update(String statementId, Object... params) throws ClassNotFoundException, SQLException,
            NoSuchFieldException, IllegalAccessException, InstantiationException {
        MappedStatement mappedStatement = configuration.getMappedStatementMap().get(statementId);
        return executor.update(configuration, mappedStatement, params);
    }

    @Override
    public int delete(String statementId, Object... params) throws ClassNotFoundException, SQLException,
            NoSuchFieldException, IllegalAccessException, InstantiationException {
        MappedStatement mappedStatement = configuration.getMappedStatementMap().get(statementId);
        return executor.update(configuration, mappedStatement, params);
    }

    @Override
    public <T> T getMapper(Class<?> mapperClass) {
        // 使用JDK动态代理来为接口生成代理对象，并返回
        Object proxyInstance = Proxy.newProxyInstance(DefaultSqlSession.class.getClassLoader(), new Class[]{mapperClass},
                new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                // 1.statementId: 接口全限定名 + 接口名称
                // 方法名
                String methodName = method.getName();
                // 接口全限定名
                String className = method.getDeclaringClass().getName();
                String statementId = className + "." + methodName;

                // 获取sql操作类型
                MappedStatement mappedStatement = configuration.getMappedStatementMap().get(statementId);
                SqlCommandType sqlCommandType = mappedStatement.getSqlCommandType();
                Object result = null;
                if (mappedStatement != null && sqlCommandType != null) {
                    switch (sqlCommandType) {
                        case INSERT:{
                            result = insert(statementId, args);
                            break;
                        }
                        case UPDATE:{
                            result = update(statementId, args);
                            break;
                        }
                        case SELECT:{
                            // 获取方法返回值类型
                            Type genericReturnType = method.getGenericReturnType();

                            // 判断是否实现泛型类型参数化
                            if (genericReturnType instanceof ParameterizedType && !(genericReturnType instanceof Map || "java.util.Map".equals(((ParameterizedType) genericReturnType).getRawType().getTypeName()) || "map".equals(((ParameterizedType) genericReturnType).getRawType().getTypeName()))) {
                                // 2.params 参数：args
                                result = selectList(statementId, args);
                            } else {
                                // 2.params 参数：args
                                result = selectOne(statementId, args);
                            }
                            break;
                        }
                        case DELETE:{
                            result = delete(statementId, args);
                            break;
                        }
                    }
                }
                return result;
            }
        });
        return (T) proxyInstance;
    }

    @Override
    public void close() throws SQLException {
        executor.close();
    }

    @Override
    public void commit() throws SQLException {
        executor.commit();
    }

    @Override
    public void rollback() throws SQLException {
        executor.rollback();
    }
}
